<?php
namespace app\serveruser\logic;

use think\Db;
use \app\manage\logic\BaseLogic;

/**
 * 权限管理的逻辑层
 * @author adv30 <adv30@126.com> 2017年6月1日9:50:24
 */
class Auth extends BaseLogic
{
    protected $name = 'auth';
    protected $config = 'db_config_user';
    private $authModel = '\app\serveruser\model\Auth';
    private $authRoleMolel = '\app\serveruser\model\AuthRole';
    // 增加一条权限记录
    public function add(array $data): array
    {
        $data['status'] = '1';
        try{
            $res = $this->model($this->authModel)->save($data);
        }catch (\Exception $e) {
            // 当唯一键重复等报错时
            return server_err(null, '数据库异常:' . $e->getMessage());
        }
        $res && $res = $this->model($this->authModel)->getLastInsID();
        return auto_return($res, '成功增加一条权限记录', '增加一条权限记录失败');
    }
    // 编辑一条权限
    public function edit(array $data): array
    {
        $oldInfo = $this->model($this->authModel)->find($data['id']);
        if (!$oldInfo) {
            return \verify_err(null, '没有找到相关权限信息');
        }
        $oldInfo = $oldInfo->toArray();

        $data = \make_map($data);
        $mergeInfo = array_merge($oldInfo, $data);
        $mergeInfo['merge_auth'] = $mergeInfo['server'] . '/' . $mergeInfo['module'] . '/' .  $mergeInfo['controller'] . '/' .  $mergeInfo['action'];
        $save = \make_map($mergeInfo, ['name', 'app_name', 'server', 'module', 'controller', 'action', 'merge_auth']);
        if ($data['other_check'] !== '{}') {
            $save['other_check'] = $data['other_check'];
        }
        $res = $this->model($this->authModel)->save($save, ['id' => $data['id']]);

        return auto_return($res, '成功编辑一条权限', '编辑一条权限失败');
    }
    // 停用一条权限记录
    public function stop(array $data): array
    {
        $_where['id'] = $data['id'];
        $res = $this->model($this->authModel)->where($_where)->update(['status' => '0']);
        return auto_return($res, '成功停用一条权限记录', '停用一条权限记录失败');
    }
    // 启用一条权限记录
    public function start(array $data): array
    {
        $_where['id'] = $data['id'];
        $res = $this->model($this->authModel)->where($_where)->update(['status' => '1']);

        return auto_return($res, '成功启用一条权限记录', '启用一条权限记录失败');
    }
    // 获取权限列表分页数据
    public function list(array $data): array
    {   
        $_where['status'] = ['egt', 0];
        if(isset($data['keywords']) && $data['keywords']){ $_where['name'] = ['like', '%' . $data['keywords'] . '%']; }
        $res = $this->model($this->authModel)
                    ->where($_where)
                    ->order('id desc')
                    ->paginate($data['list_rows'], false, ['page'=>$data['page']])
                    ->toArray();
        return auto_return_page($res);
    }
    // 对数据进行转换
    private function _columeNumber(string $group, string $key, string $val): array
    {
        $res = $this->db()
                    ->field('`' . $key . '`,COUNT(*) AS `' . $val . '`')
                    ->group($group)
                    ->where(['status'=>['egt', 0]])
                    ->select();
        $list = [];
        foreach($res as $k => $v){
            $list[$v[$key]] = $v[$val];
        }
        return $list;
    }

    # 获取所有可用的权限列表
    # 一个很烂的实现方法,如有更好的方法请告诉我 李全春 <adv30@126.com> 2017年6月2日16:25:00
    public function tree(): array
    {
        // SELECT `server`,COUNT(*) AS `server_number` FROM `new-think-user`.`tp_auth` GROUP BY `server`;
        $serverNumber = $this->_columeNumber('`server`', 'server', 'server_number');
        // SELECT `module`,COUNT(*) AS `module_number` FROM `new-think-user`.`tp_auth` GROUP BY `server`,`module`;
        $moduleNumber = $this->_columeNumber('`server`,`module`', 'module', 'module_number');
        // SELECT `controller`,COUNT(*) AS `controller_number` FROM `new-think-user`.`tp_auth` GROUP BY `server`,`module`,`controller`;
        $controllerNumber = $this->_columeNumber('`server`,`module`,`controller`', 'controller', 'controller_number');

        $_where['status'] = ['egt', 0];
        $list = $this->model($this->authModel)->where($_where)->select();
        if(!$list){
            return null_data(null, '没有可用的权限列表');
        }
        $res = [];
        foreach($list as $k=>$v){
            $res[$v['server']][] = $v;
        }
        $list = $res;
        $res = [];
        foreach($list as $k=>$v){
            foreach($v as $kk=>$vv){
                $res[$k][$vv['module']][] = $vv;
            }
        }
        $list = $res;
        $res = [];
        foreach($list as $k=>$v){
            $kData = [
                'name' => $k,
                'number' => $serverNumber[$k],
                'isShow' => '0',
                'jiangzhe' => [],
                'sub' => []
            ];
            foreach($v as $kk=>$vv){
                $kkData = [
                    'name' => $kk,
                    'number' => $moduleNumber[$kk],
                    'isShow' => '0',
                    'jiangzhe' => [],
                    'sub' => []
                ];
                foreach($vv as $kkk=>$vvv){
                    $kkkData = [
                        'name' => $vvv['controller'],
                        'number' => $controllerNumber[$vvv['controller']],
                        'isShow' => '0',
                        'jiangzhe' => [],
                    ];
                    $vvvArr = $vvv->toArray();
                    $kkkData['sub'][] = [
                        'name' => $vvv['action'],
                        'number' => '1',
                        'isShow' => '0',
                        'jiangzhe' => $vvvArr['id'],
                        'sub' => []
                    ];
                    $kkkData['jiangzhe'][] = $vvvArr['id'];
                    $kkData['jiangzhe'][] = $vvvArr['id'];
                    $kData['jiangzhe'][] = $vvvArr['id'];
                    $kkData['sub'][] = $kkkData;
                }
                $kData['sub'][] = $kkData;
            }
            
            $res[] = $kData;
        }
        return auto_return($res, '成功获取可用权限列表', '获取可用权限列表失败');
    }
    // 给某个角色一个权限(关系表)
    public function addAuthByRole(array $data): array
    {
        $checkRes = $this->_getValidIds($data['auth_id']);
 
        if (\SUCCESS_STATUS !== $checkRes['status']) {
            return $checkRes;
        }

        $data['status'] = '1';
        try{
             $res = $this->model($this->authRoleMolel)->save($data);
        }catch (\Exception $e) {
            // 当唯一键重复等报错时
            return server_err(null, '数据库异常:' . $e->getMessage());
        }

        $res && $res = $this->model($this->authRoleMolel)->getLastInsID();
        return auto_return($res, '给某个角色一个权限成功', '给某个角色一个权限失败');
    }
    // 给某个角色N个权限(关系表)
    public function addAuthsByRole(array $data): array
    {
        $checkRes = $this->_getValidIds($data['auth_ids'], false);
        if (\SUCCESS_STATUS !== $checkRes['status']) {
            return $checkRes;
        } else {
            $data['auth_ids'] = $checkRes['res']['output_ids'];
        }
        $save = [];
        $idsArr = explode(',', $data['auth_ids']);
        foreach ($idsArr as $k => $v) {
            $save[] = ['auth_id' => $v, 'role_id' => $data['role_id'], 'status' => '1'];
        }
        $count = count($idsArr);
        try{
             $res = $this->model($this->authRoleMolel)->saveAll($save);
        }catch (\Exception $e) {
            // 当唯一键重复等报错时
            return server_err(null, '数据库异常:' . $e->getMessage());
        }

        return auto_return($res, '给某个角色' . $count . '个权限成功', '给某个角色' . $count . '个权限失败');
    }
    // 移除某个角色N个权限(关系表)
    public function removeAuthsByRole(array $data): array
    {
        $checkRes = $this->_getValidIds($data['auth_ids'], false);
        if (\SUCCESS_STATUS !== $checkRes['status']) {
            return $checkRes;
        } else {
            $data['auth_ids'] = $checkRes['res']['output_ids'];
        }
        $_where['role_id'] = $data['role_id'];
        $_where['auth_id'] = ['in', $data['auth_ids']];

        $res = $this->model($this->authRoleMolel)->where($_where)->delete();

        return auto_return($res, '移除某个角色相关权限成功', '移除某个角色相关权限失败');
    }
    // 禁用某个角色的所有权限
    public function stopByRole(array $data): array
    {
        $_where['role_id'] = $data['role_id'];
        $save['status'] = '0';
        $res = $this->model($this->authRoleMolel)->where($_where)->update($save);
        return auto_return($res, '禁用某个角色的所有权限成功', '禁用某个角色的所有权限失败');
    }
    // 启用某个角色的所有权限
    public function startByRole(array $data): array
    {
        $_where['role_id'] = $data['role_id'];
        $save['status'] = '1';
        $res = $this->model($this->authRoleMolel)->where($_where)->update($save);
        return auto_return($res, '启用某个角色的所有权限成功', '启用某个角色的所有权限失败');
    }
    // 获取某个角色的权限列表分页
    public function listByRole(array $data): array
    {
        $_where['auth_role.role_id'] = $data['have'] ? ['eq', $data['role_id']] : ['neq', $data['role_id']];
        $_where['auth_role.status'] = '1';
//        $res = $this->model($this->authRoleMolel)
//                    ->where($_where)
//                    ->paginate($data['list_rows'], false, ['page'=>$data['page']])
//                    ->toArray();
        $res = Db::connect(config('db_config_user'))
            ->view('auth_role','role_id, auth_id, status as audit_status, create_time')
            ->view('auth','id, name','auth.id = auth_role.auth_id')
            ->where($_where)
            ->paginate($data['list_rows'], false, ['page'=>$data['page']])
            ->toArray();
        return auto_return($res, '获取某个角色的权限列表分页成功', '获取某个角色的权限列表分页失败');
    }
    // 获取某个角色的权限所有权限列表数据
    public function treeByRole(array $data): array
    {
        $_where['role_id'] = $data['role_id'];
        $_where['status'] = '1';
        $res = $this->model($this->authRoleMolel)
                    ->where($_where)
                    ->select();
        return auto_return($res, '获取某个角色的权限所有权限列表数据成功', '获取某个角色的权限所有权限列表数据失败');
    }
    // 获取指定ids的权限
    public function listByIds(array $data): array
    {
        $_where['id'] = ['in', $data['ids']];
        $list = $this->model($this->authModel)
                    ->where($_where)
                    ->select();
        return auto_return($list, '成功获取权限', '没有相关权限');
    }
    // 从redis获取一个角色集的权限,如没有则从mysql数据库中更新一次至redis
    public function getAuthsByRoles(array $data): array
    {
        $redis = redis();
        $key = AUTHS_FRIFIX . $data['roles'];
        // 从redis中判断是否具有某种角色集
        $exists = $redis->exists($key);
        // 如果值存在
        if($exists){
            $authList = $redis->sMembers($key);
        } else {
            $authResInfo = $this->_rolesFromMysql($data);
            if(SUCCESS_STATUS !== $authResInfo['status']){
                return $authResInfo;
            }
            $data['authList'] = $authList = $authResInfo['res'];
            //将角色集对应的权限数据设置到redis中
            $this->_setRolesToRedis($data, $redis);
        }
        return auto_return($authList, '成功获取该角色集对应的权限列表', '获取该角色集对应的权限列表失败');
    }
    // 从mysql数据库读[角色集的权限]
    private function _rolesFromMysql(array $data): array
    {
        $role = logic('\app\serveruser\logic\Role');
        $idsInfo = $role->getIdsByRoles($data);
        if (SUCCESS_STATUS !== $idsInfo['status']){
            return $idsInfo;
        }
        $ids = $idsInfo['res']['ids'];
        $list = \think\Db::connect(config('db_config_user'))
                        ->view('auth_role', 'auth_id')
                        ->view('auth', 'merge_auth', 'auth_role.auth_id=auth.id', 'LEFT')
                        ->where(['auth.status' => 1, 'auth_role.status' => 1, 'auth_role.role_id' => ['in', $ids]])
                        ->select();
        $authList = [];
        foreach($list as $k => $v){
            $authList[] = $v['merge_auth'];
        }
        return auto_return($authList, '成功获取该角色权限集', '该角色没有权限集');
    }
    // 将角色集对应的权限数据设置到redis中
    private function _setRolesToRedis(array $data, \Redis $redis = null): bool
    {
        $redis ?? $redis = redis();
        $key = AUTHS_FRIFIX . $data['roles'];
        foreach ($data['authList'] as $auth) {
            $redis->sAdd($key, $auth);
        }
        $redis->expire($key, AUTH_EXPIRE);
        return true;
    }
    /**
     * 传入一堆IDS返回权限表中所可使用的IDS
     * $equality 是返回成功的状态码是否是传入的ids数量和传出的数量相等,还是只要有数据返回就成功
     */
    private function _getValidIds(string $ids, bool $equality = true): array
    {
        $inputCount = count(explode(',', $ids));
        $_where['status'] = '1';
        $_where['id'] = ['in', $ids];
        $list = $this->model($this->authModel)
            ->field('id')
            ->where($_where)
            ->select();
 
        $outputCount = count($list);

        $list = $list 
                    ? $outputCount === 1
                        ? $list[0]['id']
                        : implode(',', $list) 
                    : '';

        if ($equality) {
            $status = ($inputCount === $outputCount);
        } else {
            $status = !!$list;
        }
        if ($status) {
            return auto_success(['input_ids' => $ids, 'output_ids' => $list], '成功验证可用权限IDS');
        } else {
            return auto_failure(['input_ids' => $ids, 'output_ids' => $list], '验证可用权限IDS失败');
        }
    }

    public function roleByAuth(array $data): array
    {
        $roleList = Db::connect(config('db_config_user'))->view('role','*')->select();
        $roleByAuthList = Db::connect(config('db_config_user'))
                        ->view('auth_role','role_id')
                        ->view('role','*','role.id = auth_role.role_id')
                        ->where('auth_role.auth_id', 'eq', $data['auth_id'])
                        ->select();
        $roleListId = [];
        $roleByAuthListId = [];

        foreach ($roleList as $k => $v) {
            $roleListId[] = $v['id'];
        }
        foreach ($roleByAuthList as $k => $v) {
            $roleByAuthListId[] = $v['role_id'];
        }
        $noByAuthListId = array_diff($roleListId, $roleByAuthListId);
        $noByAuthList = []; //未拥有该权限的角色
        foreach ($roleList as $k => $v) {
            if (in_array($v['id'], $noByAuthListId)) {
                $noByAuthList[] = $v;
            }
        }
        for ($i=0; $i<count($roleByAuthList); $i++) {
            $roleByAuthList[$i]["authStatus"] = 1;
            $roleByAuthList[$i]["auth_text"] = "已绑定";
        }
        for ($i=0; $i<count($noByAuthList); $i++) {
            $noByAuthList[$i]["authStatus"] = 0;
            $noByAuthList[$i]["auth_text"] = "未绑定";
        }
        $roleByAuthStatusList = array_merge($roleByAuthList,$noByAuthList);

        return auto_success($roleByAuthStatusList,'角色列表获取成功');
    }
    //根据id获取该条权限记录
    public function authInfo($data): array 
    {
        $_where['id'] = $data['id'];
        $info = $this->model($this->authModel)->where($_where)->find();
        return auto_return($info);
    }
}
